package com.yangleping.springframework.aop.aspectj;

import com.yangleping.springframework.aop.ClassFilter;
import com.yangleping.springframework.aop.MethodMatcher;
import com.yangleping.springframework.aop.Pointcut;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * 实现了 {@link Pointcut} 接口的 AspectJ 表达式切点。
 * 该类使用 AspectJ 的 PointcutExpression 来解析和匹配类和方法。
 *
 * @author yangleping
 */
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {

    /**
     * 支持的 AspectJ 切点原语集合。
     * 目前只支持 EXECUTION 原语。
     */
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();

    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    /**
     * 解析后的 AspectJ 切点表达式。
     */
    private final PointcutExpression pointcutExpression;

    /**
     * 构造函数，用于初始化 AspectjExpressionPointcut。
     *
     * @param expression AspectJ 切点表达式字符串。
     */
    public AspectJExpressionPointcut(String expression) {
        PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
                SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
        pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 检查给定的方法是否匹配切点表达式。
     *
     * @param method 要检查的方法。
     * @param targetClass 方法所属的目标类。
     * @return 如果方法匹配切点表达式，返回 true；否则返回 false。
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    /**
     * 获取类过滤器，该过滤器用于决定哪些类应该被增强。
     *
     * @return 当前实例，因为它实现了 ClassFilter 接口。
     */
    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    /**
     * 获取方法匹配器，该匹配器用于决定哪些方法应该被拦截。
     *
     * @return 当前实例，因为它实现了 MethodMatcher 接口。
     */
    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

    /**
     * 检查给定的类是否匹配切点表达式。
     *
     * @param clazz 要检查的类。
     * @return 如果类匹配切点表达式，返回 true；否则返回 false。
     */
    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }
}
